package com.ww.springboot.boot.thread.study.base.lock.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 锁
 * 1.锁的获取与释放
 *    --其实就是控制state的值
 *    获取:获取锁 则其他不满足条件的线程都获取不到锁 被阻塞
 *    释放:释放锁 判断是否有线程被阻塞 如果有则按顺序分配锁 被分配到锁的线程则可以继续执行
 * 2.锁阻塞实现
 *     LockSupport.park(node.thread); -阻塞           LockSupport.unpark(node.thread);-解阻塞
 *
 * 3.自旋- 同步器有一个同步队列 Node
 *     节点进入同步队列之后，就进入了一个自旋的过程，每个节点（或者说每个线程）都在自省地观察，当条件满足，获取到了同步状态，就可以从这个自旋过程中退出，否则依旧留在这个自旋过程中（并会阻塞节点的线程）
 *     条件-》1.前驱节点为头节点 2.获取到锁 则释放否则只能继续等待
 * 4.重入锁为什么需要将state累加 累减
 *     只有累加 累减后才能确保所有获取锁的进程都执行完了 并且都允许释放锁了
 *
 * 5.读写锁,共享锁待学习！！！！
 *
 * 6.同步器 同步队列不响应中断
 *    因为尝试获取锁时将加到同步队列的线程中断标识设置为true了; acquire->selfInterrupt
 *
 * 7.获取锁等待进入同步队列 与wait进入阻塞队列 两者完全不一样！！不要混淆
 *
 * 8.当调用signal唤醒等待队列线程时  会调用enq方法 将等待队列移动到同步队列尾端 并唤醒线程 等待获取线程锁
 *   等待队列顺序 不代表最终获取锁的顺序 而是由唤醒顺序决定的
 *
 * 9.waitStatus 阻塞队列节点状态 -- -1 0 1 2 3 正数等待操作
 *
 * 10.同步队列-(node) && 阻塞队列-(Condition->waiter)
 */
@Slf4j
class MutexDemo {

    private static Mutex lock = new Mutex();
    private static Condition conditionA = lock.newCondition();
    private static Boolean isEnd = false;

    public static void main(String[] args) throws InterruptedException {
//        new Thread(() -> {
//            int i = 0;
//            while (!isEnd) {
//                Boolean flag = lock.tryLock();
//                System.out.println("是否抢到锁" + flag);
//                try {
//                    i++;
//                    if (flag) {
//                        System.out.println("抢到锁就休眠一秒钟!");
//                        if(i>10){
//                            lock.unlock();
//                        }
//                        TimeUnit.MILLISECONDS.sleep(100);
//                    }
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();

        for (int i = 0; i < 10; i++) {
            TimeUnit.SECONDS.sleep(1);
            int finalI = i;
            new Thread(() -> {
                lock.lock();
                try {
                    System.out.println("是否有锁等待:" + lock.hasQueuedThreads());
                    System.out.println("是否锁占用:" + lock.isLocked());
                    conditionA.await();
                    System.out.println("是否有锁等待2:" + lock.hasQueuedThreads());
                    System.out.println("是否锁占用:" + lock.isLocked());
                    //System.out.println("解锁"+ finalI);
                    System.out.println(Thread.currentThread());
                    System.out.println("解锁");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }

            }).start();
        }

        TimeUnit.SECONDS.sleep(3);
        lock.lock();
        conditionA.signalAll();
        lock.unlock();
        System.out.println("----------------解锁开始---------------------");

        isEnd = true;

        //TimeUnit.SECONDS.sleep(1);

//        for (int i = 0; i < 10; i++) {
//            lock.lock();
//            conditionA.signalAll();
//            lock.unlock();
//            System.out.println("----------------解锁开始2---------------------");
//        }


//        for (int i = 0; i < 10; i++) {
//            TimeUnit.SECONDS.sleep(2);
//            lock.lock();
//            try {
//                conditionA.signal();
//            } finally {
//                lock.unlock();
//            }
//
//        }
    }

}